package com.wrh.draw.bean;

import com.wrh.draw.exception.OutOfBoundException;

public class GridData {
    protected int xNum;
    protected int yNum;
    protected float startX;
    protected float startY;
    protected float endX;
    protected float endY;
    protected float xRes;
    protected float yRes;
    protected float undefVal;
    protected float[][] grid;

    public GridData() {
        this.undefVal = -999999.0F;
    }

    public GridData(float startX, float startY, float endX, float endY, float[][] grid) {
        this.undefVal = -999999.0F;
        this.yNum = grid.length;
        this.xNum = grid[0].length;
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
        this.xRes = (this.endX - this.startX) / (float)(this.xNum - 1);
        this.yRes = (this.endY - this.startY) / (float)(this.yNum - 1);
        this.grid = grid;
    }

    public GridData(float startX, float startY, float endX, float endY, float[][] grid, float undefVal) {
        this(startX, startY, endX, endY, grid);
        this.undefVal = undefVal;
    }

    public GridData cut(float startX, float startY, float endX, float endY) {
        int xStartIndex = (int)Math.floor((double)((startX - this.startX) / this.xRes));
        int yStartIndex = (int)Math.floor((double)((startY - this.startY) / this.yRes));
        int xEndIndex = (int)Math.ceil((double)((endX - this.startX) / this.xRes));
        int yEndIndex = (int)Math.ceil((double)((endY - this.startY) / this.yRes));
        int xNum = Math.abs(xEndIndex - xStartIndex) + 1;
        int yNum = Math.abs(yEndIndex - yStartIndex) + 1;
        float[][] grid = new float[yNum][xNum];
        int yIndex = yStartIndex;
        int xGrow = xStartIndex < xEndIndex ? 1 : -1;
        int yGrow = yStartIndex < yEndIndex ? 1 : -1;

        for(int i = 0; i < yNum; yIndex += yGrow) {
            int xIndex = xStartIndex;

            for(int j = 0; j < xNum; xIndex += xGrow) {
                if (xIndex >= 0 && xIndex < this.xNum && yIndex >= 0 && yIndex < this.yNum) {
                    grid[i][j] = this.grid[yIndex][xIndex];
                } else {
                    grid[i][j] = this.undefVal;
                }

                ++j;
            }

            ++i;
        }

        return new GridData(startX, startY, endX, endY, grid, this.undefVal);
    }

    public GridData reverseY() {
        float[][] newGrid = new float[this.yNum][];

        for(int i = 0; i < this.yNum; ++i) {
            newGrid[i] = this.grid[this.yNum - i - 1];
        }

        GridData gridData = new GridData(this.startX, this.endY, this.endX, this.startY, newGrid);
        return gridData;
    }

    public GridData cutAndInter(float startX, float startY, float endX, float endY, int xNum, int yNum, GridData.InterType interType) {
        float xRes = (endX - startX) / (float)(xNum - 1);
        float yRes = (endY - startY) / (float)(yNum - 1);
        float[][] grid = new float[yNum][xNum];

        for(int i = 0; i < yNum; ++i) {
            float y = startY + (float)i * yRes;

            for(int j = 0; j < xNum; ++j) {
                float x = startX + (float)j * xRes;

                try {
                    if (interType == GridData.InterType.DOUBLE_LINEAR) {
                        grid[i][j] = this.getValue_DoubleLinear(x, y);
                    } else {
                        grid[i][j] = this.getValue_Nearest(x, y);
                    }
                } catch (OutOfBoundException var16) {
                    grid[i][j] = this.undefVal;
                }
            }
        }

        return new GridData(startX, startY, endX, endY, grid, this.undefVal);
    }

    public float getValue_Nearest(float x, float y) throws OutOfBoundException {
        float val = this.undefVal;
        int xIndex = (int)((x - this.startX) / this.xRes);
        int yIndex = (int)((y - this.startY) / this.yRes);
        if (xIndex >= 0 && xIndex < this.xNum && yIndex >= 0 && yIndex < this.yNum) {
            val = this.grid[yIndex][xIndex];
            return val;
        } else {
            throw new OutOfBoundException();
        }
    }

    public float getValue_DoubleLinear(float x, float y) throws OutOfBoundException {
        float val = this.undefVal;
        float xIdx = (x - this.startX) / this.xRes;
        float yIdx = (y - this.startY) / this.yRes;
        int xIndex = (int)Math.floor((double)((x - this.startX) / this.xRes));
        int yIndex = (int)Math.floor((double)((y - this.startY) / this.yRes));
        float w1 = ((float)(yIndex + 1) - yIdx) * ((float)(xIndex + 1) - xIdx);
        float w2 = ((float)(yIndex + 1) - yIdx) * (xIdx - (float)xIndex);
        float w3 = (yIdx - (float)yIndex) * ((float)(xIndex + 1) - xIdx);
        float w4 = (yIdx - (float)yIndex) * (xIdx - (float)xIndex);
        float v1 = this.isOutOfBound(xIndex, yIndex) ? this.undefVal : this.grid[yIndex][xIndex];
        float v2 = this.isOutOfBound(xIndex + 1, yIndex) ? this.undefVal : this.grid[yIndex][xIndex + 1];
        float v3 = this.isOutOfBound(xIndex, yIndex + 1) ? this.undefVal : this.grid[yIndex + 1][xIndex];
        float v4 = this.isOutOfBound(xIndex + 1, yIndex + 1) ? this.undefVal : this.grid[yIndex + 1][xIndex + 1];
        if (v1 == this.undefVal) {
            w1 = 0.0F;
        }

        if (v2 == this.undefVal) {
            w2 = 0.0F;
        }

        if (v3 == this.undefVal) {
            w3 = 0.0F;
        }

        if (v4 == this.undefVal) {
            w4 = 0.0F;
        }

        if (v1 == this.undefVal && v2 == this.undefVal && v3 == this.undefVal && v4 == this.undefVal) {
            val = this.undefVal;
        } else {
            float sw = w1 + w2 + w3 + w4;
            val = v1 * w1 / w4 + v2 * w2 / w4 + v3 * w3 / w4 + v4 * w4 / w4;
        }

        return val;
    }

    private boolean isOutOfBound(int xIndex, int yIndex) {
        return xIndex < 0 || xIndex >= this.xNum || yIndex < 0 || yIndex >= this.yNum;
    }

    public int getxNum() {
        return this.xNum;
    }

    public void setxNum(int xNum) {
        this.xNum = xNum;
    }

    public int getyNum() {
        return this.yNum;
    }

    public void setyNum(int yNum) {
        this.yNum = yNum;
    }

    public float getStartX() {
        return this.startX;
    }

    public void setStartX(float startX) {
        this.startX = startX;
    }

    public float getStartY() {
        return this.startY;
    }

    public void setStartY(float startY) {
        this.startY = startY;
    }

    public float getEndX() {
        return this.endX;
    }

    public void setEndX(float endX) {
        this.endX = endX;
    }

    public float getEndY() {
        return this.endY;
    }

    public void setEndY(float endY) {
        this.endY = endY;
    }

    public float getxRes() {
        return this.xRes;
    }

    public void setxRes(float xRes) {
        this.xRes = xRes;
    }

    public float getyRes() {
        return this.yRes;
    }

    public void setyRes(float yRes) {
        this.yRes = yRes;
    }

    public float[][] getGrid() {
        return this.grid;
    }

    public void setGrid(float[][] grid) {
        this.grid = grid;
    }

    public float getUndefVal() {
        return this.undefVal;
    }

    public void setUndefVal(float undefVal) {
        this.undefVal = undefVal;
    }

    public static enum InterType {
        DOUBLE_LINEAR,
        NEAREST;

        private InterType() {
        }
    }
}
